using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Threading;
using System.Threading.Tasks;
using CollabApp.Domain.Entities;

namespace CollabApp.Domain.Repositories;

/// <summary>
/// 通用仓储接口
/// 提供基本的增删改查、条件查询、分页查询等功能
/// </summary>
/// <typeparam name="T">实体类型，必须继承BaseEntity</typeparam>
public interface IRepository<T> where T : BaseEntity
{
    // ============ 查询操作 ============
    
    /// <summary>
    /// 根据ID查询实体
    /// </summary>
    /// <param name="id">实体ID</param>
    /// <returns>实体，如果不存在则返回null</returns>
    Task<T?> GetByIdAsync(Guid id);

    /// <summary>
    /// 获取所有实体
    /// </summary>
    /// <returns>所有实体集合</returns>
    Task<IEnumerable<T>> GetAllAsync();

    /// <summary>
    /// 根据条件查询单个实体
    /// </summary>
    /// <param name="predicate">查询条件</param>
    /// <returns>符合条件的第一个实体，如果不存在则返回null</returns>
    Task<T?> GetSingleAsync(Expression<Func<T, bool>> predicate);

    /// <summary>
    /// 根据条件查询多个实体
    /// </summary>
    /// <param name="predicate">查询条件</param>
    /// <returns>符合条件的实体集合</returns>
    Task<IEnumerable<T>> GetManyAsync(Expression<Func<T, bool>> predicate);

    /// <summary>
    /// 分页查询数据
    /// </summary>
    /// <param name="predicate">查询条件表达式</param>
    /// <param name="pageIndex">页码（从0开始）</param>
    /// <param name="pageSize">每页数据量</param>
    /// <returns>返回分页后的数据集合和总数</returns>
    Task<(IEnumerable<T> Items, int TotalCount)> GetPagedAsync(
        Expression<Func<T, bool>> predicate,
        int pageIndex,
        int pageSize);

    /// <summary>
    /// 分页查询所有数据
    /// </summary>
    /// <param name="pageIndex">页码（从0开始）</param>
    /// <param name="pageSize">每页数据量</param>
    /// <returns>返回分页后的数据集合和总数</returns>
    Task<(IEnumerable<T> Items, int TotalCount)> GetPagedAsync(
        int pageIndex,
        int pageSize);

    /// <summary>
    /// 检查是否存在符合条件的实体
    /// </summary>
    /// <param name="predicate">查询条件</param>
    /// <returns>是否存在</returns>
    Task<bool> ExistsAsync(Expression<Func<T, bool>> predicate);

    /// <summary>
    /// 根据条件获取数据条数
    /// </summary>
    /// <param name="predicate">查询条件表达式</param>
    /// <returns>返回符合条件的数据条数</returns>
    Task<int> CountAsync(Expression<Func<T, bool>> predicate);

    /// <summary>
    /// 获取所有数据的总数
    /// </summary>
    /// <returns>返回所有数据的总条数</returns>
    Task<int> CountAllAsync();

    // ============ 高级查询操作 ============

    /// <summary>
    /// 根据条件查询并排序
    /// </summary>
    /// <typeparam name="TKey">排序字段类型</typeparam>
    /// <param name="predicate">查询条件</param>
    /// <param name="orderBy">排序表达式</param>
    /// <param name="ascending">是否升序，默认true</param>
    /// <returns>排序后的实体集合</returns>
    Task<IEnumerable<T>> GetOrderedAsync<TKey>(
        Expression<Func<T, bool>> predicate,
        Expression<Func<T, TKey>> orderBy,
        bool ascending = true);

    /// <summary>
    /// 获取前N条记录
    /// </summary>
    /// <param name="predicate">查询条件</param>
    /// <param name="count">获取的记录数</param>
    /// <returns>前N条记录</returns>
    Task<IEnumerable<T>> GetTopAsync(Expression<Func<T, bool>> predicate, int count);

    /// <summary>
    /// 获取前N条记录并排序
    /// </summary>
    /// <typeparam name="TKey">排序字段类型</typeparam>
    /// <param name="predicate">查询条件</param>
    /// <param name="orderBy">排序表达式</param>
    /// <param name="count">获取的记录数</param>
    /// <param name="ascending">是否升序，默认true</param>
    /// <returns>排序后的前N条记录</returns>
    Task<IEnumerable<T>> GetTopOrderedAsync<TKey>(
        Expression<Func<T, bool>> predicate,
        Expression<Func<T, TKey>> orderBy,
        int count,
        bool ascending = true);

    // ============ 增加操作 ============
    
    /// <summary>
    /// 添加单个实体
    /// </summary>
    /// <param name="entity">要添加的实体</param>
    Task AddAsync(T entity);

    /// <summary>
    /// 批量添加实体
    /// </summary>
    /// <param name="entities">要添加的实体集合</param>
    Task AddRangeAsync(IEnumerable<T> entities);

    // ============ 更新操作 ============
    
    /// <summary>
    /// 更新单个实体
    /// </summary>
    /// <param name="entity">要更新的实体</param>
    Task UpdateAsync(T entity);

    /// <summary>
    /// 批量更新实体
    /// </summary>
    /// <param name="entities">要更新的实体集合</param>
    Task UpdateRangeAsync(IEnumerable<T> entities);

    // ============ 删除操作 ============
    
    /// <summary>
    /// 删除单个实体（软删除，设置IsDeleted=true）
    /// </summary>
    /// <param name="entity">要删除的实体</param>
    Task DeleteAsync(T entity);

    /// <summary>
    /// 根据ID删除实体（软删除）
    /// </summary>
    /// <param name="id">实体ID</param>
    Task DeleteAsync(Guid id);

    /// <summary>
    /// 批量删除实体（软删除）
    /// </summary>
    /// <param name="entities">要删除的实体集合</param>
    Task DeleteRangeAsync(IEnumerable<T> entities);

    /// <summary>
    /// 根据条件批量删除实体（软删除）
    /// </summary>
    /// <param name="predicate">删除条件</param>
    Task DeleteWhereAsync(Expression<Func<T, bool>> predicate);

    // ============ 工作单元操作 ============
    
    /// <summary>
    /// 保存所有更改到数据库
    /// </summary>
    /// <param name="cancellationToken">取消令牌</param>
    /// <returns>受影响的记录数</returns>
    Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);

    // ============ 性能优化方法 ============

    /// <summary>
    /// 批量插入（高性能）- 适用于大量数据插入
    /// </summary>
    /// <param name="entities">要插入的实体集合</param>
    /// <param name="cancellationToken">取消令牌</param>
    Task BulkInsertAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default);

    /// <summary>
    /// 批量更新（高性能）- 适用于大量数据更新
    /// </summary>
    /// <param name="entities">要更新的实体集合</param>
    /// <param name="cancellationToken">取消令牌</param>
    Task BulkUpdateAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default);

    /// <summary>
    /// 批量软删除（高性能）- 直接执行SQL
    /// </summary>
    /// <param name="predicate">删除条件</param>
    /// <param name="cancellationToken">取消令牌</param>
    Task BulkSoftDeleteAsync(Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default);

    /// <summary>
    /// 检查连接是否可用
    /// </summary>
    /// <param name="cancellationToken">取消令牌</param>
    Task<bool> IsHealthyAsync(CancellationToken cancellationToken = default);
}